#include <iostream>
using namespace std;
/*
class Date  //类
{
public://公有 声明在public后面的成员所有人都是可以使用
    //void Init(Date* this,编译器增加的 存在栈中 int year,int month,int day)
    void Init(int year,int month,int day)//成员函数是一样的，放到公共区域(代码段)
    {
        _year=year;
        _month=month;
        this->_day=day;//可以调用this
        cout << this << endl; //可以在函数里面调用this 输出地址
    }
    void func1()
    {
        cout << "func()" << endl;
    }
//private://私有 只有类内的成员函数才可以访问
    int _year;  //声明 没开空间
    int _month; //成员变量是不一样的要独立存储
    int _day;
};

class A
{};//为空的类 被实例化时会有1byte的占位大小
int test1()
{
    Date d1;    //类对象实例化 -- 开空间
    //d1.Init(&d1,2023,2,2); 编译器会给d1地址给函数Init
    d1.Init(2023,2,2);
    cout << d1._year << endl;
    cout << sizeof(d1) << endl;//只有成员变量占位 成员函数在公共区域
    A A1;
    cout << sizeof(A1) << endl;//为空的类 被实例化时会有1byte的占位大小

    Date* ptr= nullptr;
    ptr->func1();    //正常运行
    (*ptr).func1();  //正常运行
    //ptr->Init(2023,2,2)   //运行崩溃  ptr是空地址 会传给this   this->_year会崩溃 this是空指针

    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————


*/
class Stack
{
public:
    //构造函数——对象实例化时编译器自动调用，函数名与类名相同，无返回值所以不用加类型，可重载
    Stack()
    {
        cout << "Stack()" << endl;

        _a= nullptr;
        _size=0;
        _capacity=0;
    }
    Stack(int n)//可以有多个构造函数
    {
        cout << "Stack(int n)" << endl;

        _a=(int*)malloc(sizeof(int)*n);//开辟空间
        if(_a== nullptr)
        {
            perror("malloc error");
            exit(-1);
        }
        _capacity=n;
        _size=0;
    }
    //析构函数——对象生命周期结束时自动调用，函数名是在类名前加上～,一个类只能有一个析构函数，不能重载
    ~Stack()
    {
        cout << "~Stack()" << endl;
        if(_a)
        {
            free(_a);
            _a = nullptr;
            _size=_capacity=0;
        }

    }
private:
    int* _a;
    int _size;
    int _capacity;
};
int test2()//构造函数和析构函数
{
    Stack st1;
    Stack st2(4);


    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



class Date2
{
public://如果写了任意一个构造函数，编译器就不会生成默认的构造函数
    Date2(int year,int month,int day)
    {
        cout << "Date2()" << endl;

        _year=year;
        _month=month;
        _day=day;
    }
    //拷贝构造
    Date2(const Date2& d)//const：防止修改引用的参数中的数据  传引用传参 如果传形参 会无限递归
    {
        cout << "Date2(const Date2& d)" << endl;

        _year=d._year;//防止写反⬆
        _month=d._month;
        _day=d._day;
    }

    bool operator==(const Date2& d)//两个参数 一个this 一个d
    {
        return _year==d._year
               && _month==d._month
               && _day==d._day;
    }

    bool operator<(const Date2& d)
    {
        return
        _year<d._year||
        _year==d._year && _month<d._month||
        _year==d._year && _month==d._month&&_day<d._day;
    }
    bool operator<=(const Date2& d)//复用
    {
        return *this == d || *this < d;
    }
    bool operator>(const Date2& d)
    {
        return !(*this <=d);
    }
    bool operator>=(const Date2& d)
    {
        return *this > d || *this == d;
    }
    bool operator!=(const Date2& d)
    {
        return !(*this == d);
    }

    Date2& operator=(const Date2& d)//返回引用参数 支持连续赋值 d1=d2=d3
    {
        if(this==&d) return *this;//d1=d1自己给自己赋值直接返回
        _year=d._year;
        _month=d._month;
        _day=d._day;
        return *this;
    }
    void Print()
    {
        cout << _year << " ";
        cout << _month << " ";
        cout << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};
class MyQueue
{
public:
    //默认生成的构造函数对内置类型不处理，只处理自定义类型
    void Print()
    {
        _day=10;//假如这个是构造函数内的
        cout << _year << " ";
        cout << _month << " ";
        cout << _day << endl;
    }

    Stack _pushST;
    Stack _popST;
    int size;//clion编译器初始化会变成 1
private:
    //声明位置给缺省值，如果没自定义构造函数，则内置类型用缺省值
    int _year=2023;
    int _month=2;
    int _day=3;
};
//tip:内置类型：int/char/double.... 自定义类型：class/struct.....
//默认生成的构造函数、析构函数，不处理内置类型，处理自定义类型

int test3()//默认生成构造和析构函数、拷贝构造
{   //tip：如果没写上面两个构造函数
    //Date2 d1(); (年月日是随机值) 可以编译，用编译器自动生成的 无参的构造函数，
    Date2 d1(2023,2,3);
    //拷贝构造
    Date2 d2(d1); //两种拷贝
    Date2 d3=d1;

    //默认构造、析构函数测试
    MyQueue q;
    q.Print();


    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



typedef int DateType;
class Stack2
{
public:
//    Stack2()
//    {
//        cout << "Stack2()" << endl;
//
//        _array= nullptr;
//        _size=0;
//        _capacity=0;
//    }
    Stack2(int n=10)//tip：全缺省构造和无参构造冲突，半缺省不会
    {
        cout << "Stack2(int n=10)" << endl;

        _array=(DateType *)malloc(sizeof(DateType)*n);
        if(_array== nullptr)
        {
            perror("malloc error");
            exit(-1);
        }
        _capacity=n;
        _size=0;
    }
    Stack2(const Stack2& st)//深拷贝 如果不开辟空间再拷贝过去，st1._array和st2._array会共用一个地址，这个地址被析构两次 会崩溃
    {
        cout << "Stack2(const Stack2& st)" << endl;

        _array=(DateType*)malloc(sizeof(DateType)*st._size);
        if(_array== nullptr)
        {
            perror("malloc error");
            exit(-1);
        }
        _size=st._size;
        _capacity=st._capacity;
        memcpy(_array,st._array,st._capacity);
    }

    ~Stack2()
    {
        cout << "~Stack2()" << endl;
        if(_array)
        {
            free(_array);
            _array = nullptr;
            _size=_capacity=0;
        }

    }
private:
    DateType* _array;
    int _size;
    int _capacity;
};
int test4()//深 拷贝函数
{
    Stack2 st;//tip：无参(不加括号)使用的是全缺省构造，编译器分不出来全缺省和无参构造，会冲突
    Stack2 st1(20);

    //把st1中的数据复制倒st2中，这种情况st1和st2的_array地址是一样的，当其中一个析构后，另一个再次析构会崩溃
    Stack2 st2(st1);
    //和栈一样 先进后析构，后进的先析构
    return  0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



//由于访问不了私有 所以直接封装到calss类中
//bool operator==(const Date2& d1,const Date2& d2)
//{
//    return d1._year==d2._year
//        && d1._month==d2._month
//        && d1._day==d2._day;
//}
//tip:不能自己创建运算符例如operator@ X ，参数必须要有一个自定义类型
//.*(没见过的)  ::(域)  sizeof  ?:(三目运算符)  .(点)  这5个运算符不能重载
int test5()//运算符重载  用的类Date2
{
    Date2 d1(2023,3,4);
    Date2 d2(2022,2,5);
    //cout << operator==(d1,d2) << endl;
    cout << d1.operator==(d2) << endl;//可以这样用也可以直接 (d1==d2)
    cout << (d1 < d2) << endl;//符号优先级，要加括号
    d1=d2;
    d1.Print();
    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————




class AA
{
public:
    AA()
    {
        cout << "AA" << endl;
    }
    ~AA()
    {
        cout << "~AA" << endl;
    }
};
class BB {
public:
    BB() {
        cout << "BB" << endl;
    }

    ~BB() {
        cout << "~BB" << endl;
    }
};
class CC
{
public:
    CC()
    {
        cout << "CC" << endl;
    }
    ~CC()
    {
        cout << "~CC" << endl;
    }
};
class DD
{
public:
    DD()
    {
        cout << "DD" << endl;
    }
    ~DD()
    {
        cout << "~DD" << endl;
    }

};
// CC c;
int test6()//构造和析构的先后顺序 全局先构造 局部再按顺序构造(不分静态) 然后按照动态后入先析构 析构完动态后再静态，后入先析构
{
    //入栈顺序为 C A B D  出栈顺序为 B A D C
        AA a;
        BB b;//等B A 析构完后再析构D C 全局最后析构
        static DD d;
        return 0;

}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————


class Test
{
public:
    //tip：加上explicit = 不允许隐式转换
    Test()//初始化列表  冒号: 开头 逗号,分隔 大括号{}结尾
        :_a1(20)//有初始化列表中的值后就用列表中的 不用缺省
        ,_a2(30)
        ,x(1)
        ,_ref(_a1)
        //tip：初始化顺序和列表无关 和声明顺序有关
        //     如果初始化顺序错误，会得到随机值
    {
        _a1++;
        _a2--;
        cout << "Test()初始化列表" << endl;
    }
    void Print() const//const修饰 *this
    {
        cout << _a1 << endl;
    }
    Test* operator&()//取地址重载
    {
        return this;
    }
    const Test* operator&() const//取地址const重载
    {
        return this;
    }
private:
    //必须在初始化列表写的 _ref x 自定义类型
    int _a1=10;//缺省
    int _a2;
    const int x;
    int& _ref;
};
int test7()//初始化列表
{
    const Test a;
    a.Print();//是一个权限展开 要用const修饰 *this
    cout << &a <<endl;

    //Test a=1;//单参数构造函数支持隐式转换 多参数构造函数不支持
    //Test a={1,2,3}; //多参数构造函数C++11后支持
    return 0;
}



//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



class T8
{
public:
    T8()
    {
        cout << "T8()" << endl;
        ++count;
    }
    T8(const T8& a)
    {
        ++count;
    }
    static int GetCount()//静态成员函数没有this指针  和静态成员类型搭配使用
    {
        //_a++;//不能访问非静态成员
        return count;
    }

    ~T8()
    {
        cout << "~T8()" <<endl;
    }
private:
    //不属于某个对象 属于所有对象 属于整个类
    static int count; //声明 不能缺省初始化或在初始化列表中初始化
    int _a=1;
};
int T8::count=0;//全局初始化
int test8()
{
    T8 aa;
    cout << T8::GetCount() << endl;
    T8();//匿名对象 生命周期只在这一行

    return 0;
}






//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————



class Date
{
public://如果写了任意一个构造函数，编译器就不会生成默认的构造函数
    friend ostream& operator<<(ostream& out,const Date& d);//友元 可以让这个函数访问私有成员
    friend istream& operator>>(istream& in,Date& d);

    Date(int year,int month,int day)
    {
        _year=year;
        _month=month;
        _day=day;
    }
    void Print()
    {
        cout << _year << " ";
        cout << _month << " ";
        cout << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};
ostream& operator<<(ostream& out,const Date& d)//const限制权限不改变对象的值
{
    out <<d._year << "年" <<d._month <<"月"<< d._day <<"日" << endl;
    return out;
}
istream& operator>>(istream& in,Date& d)//因为要写入对象的值所以不能const了
{
    in >> d._year >>  d._month >> d._day;
    return  in;
}
int test9()
{
    Date a(2023,2,8);
    cin >> a;
    cout << a << endl;
    return 0;
}
int main()
{
    //test1();
    test2();
    //test3();
    //test4();
    //test5();
    //test6();
    //test7();
    //test8();
    //test9();
    return 0;
}

